//由一个组件，向上找最近的指定组件,findComponents 系列方法最终都是返回组件的实例，进而可以读取或调用该组件的数据和方法
//第一个是当前上下文，比如你要基于哪个组件来向上寻找，一般都是基于当前的组件，也就是传入 this；第二个参数是要找的组件的 name
export const findComponentUpward = (context, componentName) => {
  let parent = context.$parent;
  let name = parent.$options.name;
  while (parent && (!name || name !== componentName)) {
    //没有找到，进行向上查找
    parent = parent.$parent;
    if (parent) name = parent.$options.name;
  }
  //找到最近的指定组件
  return parent;
};

//由一个组件，向上找到所有的指定组件
//因为这个函数是一直向上寻找父级（parent）的，只有递归组件的父级才是自身
const findComponentsUpward = (context, componentName) => {
  let parents = [];
  const parent = context.$parent;
  if (parent) {
    if (parent.$options.name === componentName) parents.push(parent);
    return parents.concat(findComponentsUpward(parent, componentName));
  } else {
    return [];
  }
};

// 由一个组件，向下找到最近的指定组件
const findComponentDownward = (context, componentName) => {
  let childrens = context.$children; //得到的是当前组件的全部子组件
  let children = null;
  if (childrens.length) {
    for (const child of childrens) {
      const name = child.$options.name;
      if (name === componentName) {
        children = child;
        break;
      } else {
        children = findComponentDownward(child, componentName);
        if (children) break;
      }
    }
  }
  return children;
};

//由一个组件，向下找到所有的指定组件
export const findComponentsDownward = (context, componentName) => {
  return context.$children.reduce((components, child) => {
    if (child.$options.name === componentName) components.push(child);
    const foundChilds = findComponentsDownward(child, componentName);
    return components.concat(foundChilds);
  }, []);
};

// 由一个组件，找到指定组件的兄弟组件
const findBrothersComponents = (context, componentName, exceptMe = true) => {
  //寻找兄弟组件的方法，是先获取 context.$parent.$children，也就是父组件的全部子组件
  let res = context.$parent.$children.filter(item => {
    return item.$options.name === componentName;
  });
  //都会给每个组件加一个内置的属性 _uid，这个 _uid 是不会重复的，借此我们可以从一系列兄弟组件中把自己排除掉
  let index = res.findIndex(item => item._uid === context._uid);
  if (exceptMe) res.splice(index, 1);
  return res;
};

export default {
  findComponentUpward,
  findComponentsUpward,
  findComponentDownward,
  findComponentsDownward,
  findBrothersComponents
};
